//
//  ChartSocket.m
//  socket
//
//  Created by Herbert Dai on 14-10-24.
//  Copyright (c) 2014年 Herbert Dai. All rights reserved.
//

#import "ChartSocket.h"
#import "ChartSocketLogger.h"
#import <CocoaAsyncSocket/GCDAsyncSocket.h>

@interface ChartSocket(){
    UInt16 _port;
    NSString *_host;
    GCDAsyncSocket *_sock;
    NSTimer *_detectTimer;
    UInt32 _maxAttempTimes;
    UInt32 _attempTimes;
}
@end

// csrStatusMap todo
@implementation ChartSocket

static  NSData *PacketStartFlag = nil;//[NSData dataWithBytes:"UU" length:2];

- (ChartSocket *)init:(NSString *)host withPort:(UInt16)port {
    if (self = [super init]) {
        _port = port;
        _host = host;
        _attempTimes = 1;
        _maxAttempTimes = 99999999;
        _timeout = 7;
    }
    return self;
}

- (void)deallocTimer {
  [_detectTimer invalidate];
  _detectTimer = nil;
}

- (void)deallocSocket {
  [self disconnect];
  _sock = nil;
}

- (void)dealloc {
  [self deallocTimer];
  [self deallocSocket];
}

// socket 方法
// did not need delegate
- (void)connect {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSError *error = nil;
        if (_sock == nil) _sock = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        //    _sock.IPv4PreferredOverIPv6 = NO; //如果后台提供的host是域名 则不用convertHostToAddress:转换，启用本行代码即可
        
        BOOL connect = [_sock connectToHost:[self convertHostToAddress:_host]
                                     onPort:_port
                                withTimeout:self.timeout
                                      error:&error];
        chartSocketLog(@"CHARTSOCKT connect result: %d", connect);
    });
}

+ (NSData *)UUFlagData
{
    if (PacketStartFlag == nil) {
        PacketStartFlag = [NSData dataWithBytes:"\x55\x55" length:2];
    }
    return PacketStartFlag;
}

- (void)disconnect {
  [_sock disconnectAfterReadingAndWriting];
}

- (void)emit:(NSData *)data withTag:(NSInteger)tag{
  [_sock writeData:data withTimeout:-1 tag:tag];
}

// socket 方法结束

// socket状态监听
- (void)socket:(GCDAsyncSocket *)sock
    didConnectToHost:(NSString *)host
                port:(UInt16)port {
  _attempTimes = 1;
  chartSocketLog(@"ChartSocket onSocket");
  
  [_sock readDataToData:[ChartSocket UUFlagData] withTimeout:-1 tag:1];
    
  if ([self.delegate respondsToSelector:@selector(onSocketConnected)]) {
    return [self.delegate onSocketConnected];
  }
    
}

- (void)socket:(GCDAsyncSocket *)sock
     didReadData:(NSData *)data
         withTag:(long)tag {
    
    if (tag == 1) {
        //在读2位长度`
        [_sock readDataToLength:2 withTimeout:-1 tag:2];
    } else if (tag == 2) {
        UInt16 totalmsglen = 0;
        [data getBytes:&totalmsglen length:sizeof(totalmsglen)];
        
        if (totalmsglen == 0) {
            // 没数据
            [_sock readDataToData:[ChartSocket UUFlagData] withTimeout:-1 tag:1];
        } else {
            //读怎么长数据
            [_sock readDataToLength:totalmsglen withTimeout:-1 tag:3];
        }
    }
    else if (tag == 3) {
      if ([self.delegate respondsToSelector:@selector(didReadData:)]) {
         [self.delegate didReadData:data];
      }
        
      [_sock readDataToData:[ChartSocket UUFlagData] withTimeout:-1 tag:1];
    }
    

}

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
  chartSocketLog(@"data writed with the tag, %ld", tag);
  //    [[NSNotificationCenter defaultCenter]
  //    postNotificationName:@"SocketWrited" object:nil];
}

// reconnect stratgy every time add 5 seconds, fail then send a msg
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError: (NSError *)err {
  chartSocketLog(@"ChartSocket onSocketDidDisconnect");
  if ([self.delegate respondsToSelector:@selector(onSocketDisconnected)]) {
    return [self.delegate onSocketDisconnected];
  }
}

- (BOOL)isConnected
{
    return _sock && _sock.isConnected;
}
// socket 状态监听结束

-(NSString *)convertHostToAddress:(NSString *)host {
    //将host 转成适用当前网络环境的ip地址
    NSError *err = nil;
    
    NSMutableArray *addresses = [GCDAsyncSocket lookupHost:host port:0 error:&err];
    
    if (err) {
        return host;
    }
    
    NSData *address4 = nil;
    NSData *address6 = nil;
    
    for (NSData *address in addresses)
    {
        if (!address4 && [GCDAsyncSocket isIPv4Address:address])
        {
            address4 = address;
        }
        else if (!address6 && [GCDAsyncSocket isIPv6Address:address])
        {
            address6 = address;
        }
    }
    
    return [GCDAsyncSocket hostFromAddress:address6 ?: address4];
}


@end
